home *** CD-ROM | disk | FTP | other *** search
- /*
- File: PathLimit.c
-
- Contains: QuickDraw GX to PostScript conversion code.
- Routines in here deal with splitting shapes
- up into pieces that do not exceed the stinky
- PostScript path limit.
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1990-1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include "GXToPSBuildConfig.h"
- #include <GXGraphics.h>
-
- #include "PublicPostScriptIE.h"
- #include "ShapeUtilities.h"
- #include "Private.h"
-
- #ifdef resumeLabel
- #undef resumeLabel
- #endif
- #define resumeLabel(exception)
-
- /***********************************
- PSContPathPoints:
-
- count number of points. Since the number
- that will be used up by PostScript is different
- than gx graphics, we must count ourselves. This is due
- to the fact that we use cubics in PostScript and
- also that the gx graphics has implied points which must
- be accounted for.
-
- The code is the same code as is used to output
- path data
-
- *************************************/
- long PSCountPathPoints( gxShape theShape);
- long PSCountPathPoints( gxShape theShape)
- {
- Ptr inPath; // We must walk through the Paths structure
- gxShapeAttribute theAttributes;
- long i, pointIndex;
- long size;
- long firstIndex, lastIndex; // Index of first and last point ON curve.
- Boolean closeIt; // Is it open or closed.
- long nContours; // Number of contours.
- long nPoints; // Number of points in contour.
- register unsigned long* controlBitLong; // Pointer to control bits.
- register unsigned long cBitMask; // Mask for reading control bits.
- unsigned long lastBitMask; // Mask for last point in contour.
- long cBitSize; // Number of longs for control bits.
- short qIndex; // Indicates #points in curve segment so far.
- Boolean isOff; // On the curve or off the curve.
- Boolean firstIsOn, lastIsOn;
- long totalPoints = 0;
-
-
- /* If it is any fill other than frameFill we must close each contour */
-
- closeIt = !(GXGetShapeFill(theShape) == gxFrameFill);
-
- /***********
- Make sure we have access to the shape data structure,
- and then get it
- ***********/
- theAttributes = GXGetShapeAttributes(theShape);
- GXSetShapeAttributes(theShape, theAttributes | gxDirectShape);
-
- GXLockShape(theShape);
-
- inPath = (Ptr)GXGetShapeStructure(theShape, &size); //Get a pointer to the structure.
- check(inPath);
-
- nContours = ((gxPaths*)inPath)->contours; //Get the number of countours.
- inPath += sizeof(long); //Move pointer past contours field.
-
-
- /** Now count points in all of the contours **/
-
- for (i = 0; i < nContours; i++) { // Count each of the contours.
-
- nPoints = *(long*)inPath; // Get the number of points for this contour.
- inPath += sizeof(long); // Move to the data.
-
- if (nPoints > 0) {
-
- controlBitLong = (unsigned long*)inPath; // Get to the control bits.
-
- cBitSize = (nPoints + 31) / 32; // Compute the size of control bits in longs.
-
- inPath += cBitSize * sizeof(long); // Skip past control bits.
-
- cBitMask = 0x80000000U; // Initilize the mask for reading bits.
-
- lastBitMask = 0x80000000U >> ((nPoints-1) & 0x0000001F); // Mod 32
-
-
- /** Compute the first and last point on the curve **/
-
- firstIsOn = ((*controlBitLong & cBitMask) == 0);
- lastIsOn = ( ( *(controlBitLong + cBitSize - 1) & lastBitMask) == 0);
-
- if (firstIsOn && lastIsOn) { // They both are on.
-
- firstIndex = 0;
- lastIndex = nPoints;
- NEXTBIT(isOff, controlBitLong, cBitMask); // Read bit for 1st point, set up for next.
-
- } else if (firstIsOn) { // first was on, last was off
-
- firstIndex = 0;
- lastIndex = nPoints + 1;
- NEXTBIT(isOff, controlBitLong, cBitMask); // Read bit for 1st point, set up for next.
-
- } else if (lastIsOn) { // last was on, first is off
-
- lastIndex = nPoints;
- firstIndex = -1;
-
- } else { // they were both off
-
- firstIndex = -1;
- lastIndex = nPoints + 1;
-
- } //end if
-
-
- /*** count the contour ****/
-
- qIndex = 0;
- totalPoints += 1; // the first point in the contour.
-
- // Loop over all points but the first and last ON the curve.
-
- NEXTBIT(isOff, controlBitLong, cBitMask); // Check the first point in the looping.
- pointIndex = firstIndex + 1;
- while (pointIndex < (lastIndex - 1)) { // I know, should cache lastPointIndex-1
-
- if (!isOff) { // If the next point is on the curve:
-
- if ( qIndex == 0) { // If we have only q0, then do a line and start over.
-
- totalPoints += 1; // add a line segment.
-
- ++pointIndex;
-
- NEXTBIT(isOff, controlBitLong, cBitMask);
-
- } else { // We must have q0 and q1, do a curve: q0, q1, q2
-
- totalPoints += 3; // Add a curve segment.
- qIndex = 0;
- ++pointIndex;
- NEXTBIT(isOff, controlBitLong, cBitMask);
-
- }//end if
-
- } else {
-
- if (qIndex == 0) { // If we only have one point so far, this becomes 2nd.
-
- qIndex = 1;
- NEXTBIT(isOff, controlBitLong, cBitMask);
- ++pointIndex;
-
- } else { // We had 2 points, interpolate to get 3rd and to a curve
-
- totalPoints += 3; // Add a curve segment.
- qIndex = 0;
-
- }//end if
-
- }//end if
-
- }//end while
-
-
- /** Now handle the last point that is ON the curve in the contour **/
-
- if (qIndex == 0) { // If we only had one point so far, Do a line.
-
- totalPoints += 1; // Add a line segment.
-
- } else { // Else, we must have had 2 points so far, Do a curve.
-
- totalPoints += 3; // Add a curve segment.
-
- }//end if
-
- if (closeIt)
- totalPoints += 1; // Add a line segment.
-
-
- /** Point into the next contour **/
-
- inPath += nPoints * sizeof(gxPoint); // Next contour is where our next point is pointing to.
-
- }//end if
-
- }//endo for i
-
- GXSetShapeAttributes(theShape, theAttributes);
- GXUnlockShape(theShape);
-
- failed_Output:
- failed_KeepDirect:
-
- return(totalPoints);
-
- }//PSCountPathPoints
-
- //<FF>
- /***********************************
- PSCountCubicSynonymPoints:
-
- count number of points.
-
- The code is the same code as is used to output
- cubic synonym data
-
- *************************************/
- long PSCountCubicSynonymPoints(gxShape theShape);
- long PSCountCubicSynonymPoints(gxShape theShape)
- {
- gxTag cubicTag;
- Ptr cubicData;
- Ptr inCubic, endCubic;
- long dataSize;
- short instruction;
- long nPoints = 0;
-
- GXGetShapeTags(theShape, gxCubicSynonymTag, 1, 1, &cubicTag);
-
- GXLockTag(cubicTag);
- cubicData = (Ptr)GXGetTagStructure(cubicTag, &dataSize);
-
- inCubic = cubicData;
- endCubic = cubicData + dataSize;
-
- while(inCubic < endCubic) {
-
- instruction = (short)(*inCubic) & gxCubicInstructionMask;
- inCubic += sizeof(short);
-
- switch(instruction) {
-
- case gxMoveToFlag:
- ++nPoints;
- inCubic += sizeof(gxPoint);
- break;
-
- case gxLineToFlag:
- ++nPoints;
- inCubic += sizeof(gxPoint);
- break;
-
- case gxCurveToFlag:
- inCubic += 3 * sizeof(gxPoint);
- nPoints += 3;
- break;
-
- case gxClosePathFlag:
- ++nPoints;
- break;
-
- }//end switch
-
- }//end while
-
- GXUnlockTag(cubicTag);
-
- return(nPoints);
-
- }//PSCountCubicSynonymPoints
-
-
- //<FF>
- /****************************************
-
- Routine PSCountShapePoints:
-
- Routine is wrapper with same interface as
- CountShapePoints. It calls the PostScript version
- (above) for paths.
-
- This routine gets passed to DissectPath for counting.
-
- *****************************************/
- OSErr PSCountShapePoints(gxShape aShape, long contour, long *numPoints)
- {
- switch(GXGetShapeType(aShape)) {
-
- case gxPointType:
- case gxLineType:
- *numPoints = 2;
- break;
-
- case gxCurveType:
- *numPoints = 4;
- break;
-
- case gxRectangleType:
- *numPoints = 4;
- break;
-
- case gxPolygonType:
- *numPoints = GXCountShapePoints(aShape, contour);
- if (GXGetShapeFill(aShape) == gxClosedFrameFill)
- *numPoints += GXCountShapeContours(aShape); // one point per closepath.
-
- break;
-
- case gxPathType:
- if (GXGetShapeTags(aShape, gxCubicSynonymTag, 1, 1, nil))
- *numPoints = PSCountCubicSynonymPoints(aShape);
- else
- *numPoints = PSCountPathPoints(aShape);
- break;
-
- default: // All other types take up no predictable PostScript path space.
- *numPoints = 0;
- break;
-
- }//end switch
-
- return( noErr );
-
- }//PSCountShapePoints;
-
-
-
- //<FF>
- /********************************************
-
- Routine DissectShape:
-
- Routine to make sure a shape does not exceed
- the path limit. If there are very few points
- left in the pathlimit at the current level (or
- even negative - can happen when clips are really
- large because we always just subtract clip size
- from current state.) we will go to blast and
- pray mode which may cause limitchecks. Otherwise
- we will try shape-ops.
-
- *********************************************/
- #define kMinPointsDissect 50
- OSErr DissectShape(TIEGlobalsHdl hIEGlobals, gxShape *theShape)
- {
- OSErr status = noErr;
- TIEGlobalsPtr pGlobals;
- long pointsAvailable, pointCount;
- gxShape shapeCopy;
-
- pGlobals = *hIEGlobals;
-
- // Don't need to bother for noFill shapes.
- if ( GXGetShapeFill(*theShape) == gxNoFill )
- return(noErr);
-
-
- if ( GXGetShapeFill(*theShape) == gxNoFill)
- return(noErr);
-
- if (pGlobals->gStateDepth == -1)
- pointsAvailable = pGlobals->params.pathLimit;
- else
- pointsAvailable = pGlobals->gStateNest[pGlobals->gStateDepth].pointsAvail;
-
- #if DEBUGLEVEL > 1
- if (pointsAvailable < kMinPointsDissect)
- dprintf(trace, "Really low on path space: %d, disabling shape dissection - good luck!", pointsAvailable);
- #endif
-
- /******
- If the shape is biggern than the current pathlimit
- and the current path limit is greater than kMinPointsDissect,
- try to dissect - otherwise we will just blast and pray for no limitchecks.
- *****/
- status = _PSCountShapePoints(*theShape, 0, &pointCount);
- nrequire(status, failed_count);
-
- if ((pointsAvailable > kMinPointsDissect) && (pointCount > pointsAvailable)) {
-
- nrequire(status = DupShapeIfNecessary(*theShape, &shapeCopy), failed_Dup);
- *theShape = shapeCopy;
-
- status = ShUDissectPath(*theShape, pointsAvailable, true, &_PSCountShapePoints);
- nrequire(status, failed_Split);
-
- }//end if
-
- failed_Split:
- failed_Dup:
- failed_count:
-
- return(status);
-
- }//DissectShape
-